package backend

import (
	"context"
	"lanmon/internal/config"
	"net"

	"github.com/pion/mdns"
	"github.com/pkg/errors"
	"golang.org/x/net/ipv4"

	log "github.com/sirupsen/logrus"
)

type Mdns struct {
	// server
	Server *mdns.Conn
	Url    string
}

func setupMdnsServer(conf *config.Config) (*Mdns, error) {
	log.Info("launch mDNS server")
	return launchMdnsServer(conf.General.MdnsAddress)
}

func (mdns *Mdns) closeMdnsServer() error {
	if mdns.Server != nil {
		mdns.Server.Close()
	}
	return nil
}

func launchMdnsServer(url string) (*Mdns, error) {
	addr, err := net.ResolveUDPAddr("udp", mdns.DefaultAddress)
	if err != nil {
		return nil, errors.Wrap(err, "failed to resolve udp")
	}

	conn, err := net.ListenUDP("udp4", addr)
	if err != nil {
		return nil, errors.Wrap(err, "failed to resolve udp4")
	}

	mconn, err := mdns.Server(ipv4.NewPacketConn(conn), &mdns.Config{
		LocalNames: []string{url},
	})
	if err != nil {
		return nil, errors.Wrap(err, "failed to create connection")
	}

	return &Mdns{
		Server: mconn,
		Url:    url,
	}, nil
}

func setupMdnsClient(conf *config.Config) (*Mdns, error) {
	log.Info("launch mDNS client")
	return launchMdnsClient(conf.General.MdnsAddress)
}

func (mdns *Mdns) closeMdnsClient() error {
	return mdns.closeMdnsServer()
}

func launchMdnsClient(url string) (*Mdns, error) {
	addr, err := net.ResolveUDPAddr("udp", mdns.DefaultAddress)
	if err != nil {
		return nil, errors.Wrap(err, "failed to resolve udp")
	}

	conn, err := net.ListenUDP("udp4", addr)
	if err != nil {
		return nil, errors.Wrap(err, "failed to resolve udp4")
	}

	server, err := mdns.Server(ipv4.NewPacketConn(conn), &mdns.Config{})
	if err != nil {
		return nil, errors.Wrap(err, "failed to create connection")
	}

	return &Mdns{
		Server: server,
		Url:    url,
	}, nil
}

// block function
func (mdns *Mdns) lookupMdns(url string) error {
	answer, src, err := mdns.Server.Query(context.TODO(), url)
	if err != nil {
		return errors.Wrap(err, "failed to query")
	}

	log.WithFields(log.Fields{
		"answer": answer,
		"src":    src,
	}).Info("start query...")

	return nil
}
